#include "FaceEngine.h"
#include "Posture.h"
#include "Rotate.h"
#include "EngineUtils.h"

FaceEngine* FaceEngine::m_pInstance = NULL;
# ifdef __ANDROID__
MutexLock FaceEngine::m_Mutex;
#endif

FaceEngine::FaceEngine()
{
	m_minSize = 40;
}


FaceEngine::~FaceEngine()
{
	delete m_Recognizor;
	delete m_Detector;
	delete m_LandMarker;
}

cv::Mat FaceEngine::FaceRotate(cv::Mat & _faceImg, Bbox _faceBbox)
{
	Rotate rotate;
	cv::Mat rotImg;
	rotate.start(_faceImg, _faceBbox, rotImg);
	return rotImg;
}

void FaceEngine::DetectFace(cv::Mat& _rawImage,int _minSize, std::vector<Bbox>& _faceBboxes)
{
	ncnn::Mat in = ncnn::Mat::from_pixels(_rawImage.data, ncnn::Mat::PIXEL_BGR2RGB, _rawImage.cols, _rawImage.rows);
	_faceBboxes.clear();
	m_Detector->getFinalBox(in, _faceBboxes);
}

FaceEngine * FaceEngine::GetInstance()
{
	if (NULL == m_pInstance) {
		m_Mutex.lock();
		if (NULL == m_pInstance) {
			m_pInstance = new FaceEngine();
		}
		m_Mutex.unlock();
	}
	return m_pInstance;
}

void FaceEngine::Destroy()
{
	if (m_pInstance) {
		m_Mutex.lock();
		if (m_pInstance) {
			delete m_pInstance;
			m_pInstance = NULL;
		}
		m_Mutex.unlock();
	}

}

void FaceEngine::SetFaceDetectModel(const char * _modelDir)
{
	assert(_modelDir == NULL);
	m_Detector = new Detect(_modelDir);
}

void FaceEngine::SetFaceFeatureModel(const char * _modelDir)
{
	assert(_modelDir == NULL);
	m_Recognizor = new Recognize(_modelDir);
}

void FaceEngine::SetFaceMarksModel(const char * _modelDir)
{
	assert(_modelDir == NULL);
	m_LandMarker = new Mark(_modelDir);
}

void FaceEngine::SetMinFaceSize(int _minSize)
{
	m_minSize = _minSize;
}

int FaceEngine::FaceFeature(const char* _inputImgPath, float * _faceFea)
{
	if (_faceFea == nullptr) return -1;

	cv::Mat rawImage = cv::imread(_inputImgPath);
	std::vector<Bbox> faceBboxes;
	DetectFace(rawImage, m_minSize, faceBboxes);
	if (faceBboxes.size() != 1) return faceBboxes.size();		// 不只一张人脸时，返回人脸个数
	Bbox maxBbox = faceBboxes[0];
	if (maxBbox.area < m_minSize) return -1;					// 不存在人脸时，返回-1

	int swidth = maxBbox.x2 - maxBbox.x1;
	int sheight = maxBbox.y2 - maxBbox.y1;

	cv::Rect subregion(maxBbox.x1, maxBbox.y1, swidth, sheight);
	cv::Mat subimage = rawImage(subregion).clone();
	std::vector<float> markPoint;
	m_LandMarker->getMarkPoint(subimage, markPoint);		// landmark 检测姿态
	for (int i = 0; i < markPoint.size(); i++) {
		if (i % 2 == 0) markPoint[i] = markPoint[i] * subimage.cols + maxBbox.x1;
		else markPoint[i] = markPoint[i] * subimage.rows + maxBbox.y1;
	}


	// 获取姿态
	Posture posture = Posture(maxBbox, markPoint);
	int poi = posture.getPos();
	if (poi)
	{
		return poi;	// 检测姿态不满足要求，返回侧脸
	}

	// Crop人脸并旋转
	//cv::Rect faceCropROI(cv::Point2i(maxBbox.x1, maxBbox.y1), cv::Point2i(maxBbox.x2, maxBbox.y2));
	//faceCropImg = rawImage(faceCropROI);
	cv::Mat faceCropRotImg = FaceRotate(rawImage, maxBbox);


	// 识别
	ncnn::Mat in = ncnn::Mat::from_pixels(faceCropRotImg.data, ncnn::Mat::PIXEL_BGR2RGB, faceCropRotImg.cols, faceCropRotImg.rows);
	m_Recognizor->start(in, _faceFea);
	return 0;
}

int FaceEngine::FaceCropImage(const char * _inputImgPath, const char * _outImgPath)
{
	cv::Mat rawImage = cv::imread(_inputImgPath);
	std::vector<Bbox> faceBboxes;
	DetectFace(rawImage, m_minSize, faceBboxes);
	if (faceBboxes.size() != 1) return (int)faceBboxes.size();		// 不只一张人脸时，返回人脸个数
	Bbox maxBbox = faceBboxes[0];
	if (maxBbox.area < m_minSize) return -1;					// 不存在人脸时，返回-1

	// landmark 检测姿态
	int swidth = maxBbox.x2 - maxBbox.x1;
	int sheight = maxBbox.y2 - maxBbox.y1;

	cv::Rect subregion(maxBbox.x1, maxBbox.y1, swidth, sheight);
	cv::Mat subimage = rawImage(subregion).clone();
	std::vector<float> markPoint;
	m_LandMarker->getMarkPoint(subimage, markPoint);
	for (int i = 0; i < markPoint.size(); i++) {
		if (i % 2 == 0) markPoint[i] = markPoint[i] * subimage.cols + maxBbox.x1;
		else markPoint[i] = markPoint[i] * subimage.rows + maxBbox.y1;
	}

	// 获取姿态
	Posture posture = Posture(maxBbox, markPoint);
	int poi = posture.getPos();
	if (poi)
	{
		return poi;	// 检测姿态不满足要求，返回侧脸
	}

	// 截取人脸，并保存人脸
	cv::Mat cropFace;
	posture.cropByPosture(rawImage, cropFace);
	cv::resize(cropFace, cropFace, cv::Size(200, 200));
	cv::imwrite(_outImgPath, cropFace);
	return 0;
}

float FaceEngine::CalSimilar(const char * _inputImgPath1, const char * _inputImgPath2)
{
	float* fea1 = new float[FEATURE_SIZE];
	float* fea2 = new float[FEATURE_SIZE];

	// 计算特征
	int ret1 = FaceFeature(_inputImgPath1, fea1);
	int ret2 = FaceFeature(_inputImgPath2, fea2);


	// 计算相似度
	float simularity = 0.0f;
	simularity = calculSimilar(fea1, fea2, FEATURE_SIZE);
	delete fea1, fea2;
	return simularity;
}
